--第十四节 元表
local UnitlModule = require("Lua.UnitlModule");

UnitlModule.PrintTimer();

UnitlModule.PrintOperaName("元表概念");
--[[
任何表变量都可以作为另一个表变量的原表
任何表变量都可以有自己的原表（即父表）
当子表中进行一些特定操作时，会执行原表中的内容
--]]

UnitlModule.PrintOperaName("设置元表");
meta = {};
myTable = {};

--设置元表函数 setmetatable(子表，元表)
setmetatable(myTable,meta);

UnitlModule.PrintOperaName("特定操作-__tostring");

meta_2 = {--当子表要被当作字符串使用时，会默认调用这个元表中的tostring方法
    __tostring = function(t)
        return t.name;
    end
};

myTable_2 = {
    name = "张三";
};

setmetatable(myTable_2,meta_2);

print(myTable_2);


UnitlModule.PrintOperaName("特定操作-__call");

meta_3 = {
    --当子表要被当作字符串使用时，会默认调用这个元表中的tostring方法
    __tostring = function(t)
        return t.name;
    end,
    --当子表要被当作函数调用时，会默认调用这个元表中的call方法
    --当想要传参数的时候，牢记默认第一个参数是调用者自己
    __call = function(a,b)
        print(a);
        print(b);
        print("{"..a.name.."}".."哈哈哈哈");
    end
};

myTable_3 = {
    name = "张三";
};

setmetatable(myTable_3,meta_3);

--print(myTable_3);
myTable_3(1);

UnitlModule.PrintOperaName("特定操作-运算符重载");

local meta_4 = {
    --当子表使用+-*/%^运算时，会默认调用这个元表中的运算符方法，相当于运算符重载
    __add = function (val_1,val_2)
        return val_1.age + val_2.age;
    end,

    __sub = function (val_1,val_2)
        return val_1.age - val_2.age;
    end,

    __mul = function (val_1,val_2)
        return val_1.age * val_2.age;
    end,

    __div = function (val_1,val_2)
        return val_1.age / val_2.age;
    end,

    __mod = function (val_1,val_2)
        return val_1.age % val_2.age;
    end,

    __pow = function (val_1,val_2)
        return val_1.age ^ val_2.age;
    end,
    --下面的是 == > < >= <= .. ~=
     __eq = function (val_1,val_2)
        return val_1.age == val_2.age;
    end,

    __gt = function (val_1,val_2)
        return val_1.age > val_2.age;
    end,

    __lt = function (val_1,val_2)
        return val_1.age < val_2.age;
    end,

    __ge = function (val_1,val_2)
        return val_1.age >= val_2.age;
    end,

    __le = function (val_1,val_2)
        return val_1.age <= val_2.age;
    end,

    __concat = function (val_1,val_2)
        return val_1.age .. val_2.age;
    end,

    __ne = function (val_1,val_2)
        return val_1.age ~= val_2.age;
    end,
};

local myTable_4 = {
age = 6;
};

local myTable_5 = {
    age = 8;
};

setmetatable(myTable_4,meta_4);

print(myTable_4 + myTable_5);
print(myTable_4 - myTable_5);
print(myTable_4 * myTable_5);
print(myTable_4 / myTable_5);
print(myTable_4 % myTable_5);
print(myTable_4 ^ myTable_5);

--若使用条件运算符去比较两个对象
--这两个对象的原表一定要一致，才能准确调用方法
print("等于：");
print(myTable_4 == myTable_5);
print("不等于：");
print(myTable_4 ~= myTable_5);
print("大于：");
print(myTable_4 > myTable_5);
print("小于：");
print(myTable_4 < myTable_5);
print("大于等于：");
print(myTable_4 >= myTable_5);
print("小于等于：");
print(myTable_4 <= myTable_5);
print("连接：");
print(myTable_4 .. myTable_5);



UnitlModule.PrintOperaName("__index 和 __newindex");

local meta_5 = {
    __index = {name = "ASCII"};
};
--meta_5.__index = { name = "霍哈哈"};
--这两种方式都行

local myTable_6 = {};
setmetatable(myTable_6,meta_5);

--[[
__index:当子表找不到某一属性时，会到元表__index指定的表去索引数据
__index也可以指向元表自身

meta = {
    variable = 赋值,
    __index = meta; 
    这种方式的指向自己，索引出来的数据为nil
    因为这种方式的指向，元表自身都没有初始化完成
}

所以建议用这种方式: meta.__index = {指向位置};

--]]
print(myTable_6.name);


local meta_6 = {};
local myTable_7 = {};


setmetatable(myTable_7,meta_6);
meta_6.__newindex = {};
myTable_7.name = "风神一";
print(myTable_7.name); 
--输出nil，若去除meta_6.__newindex = {};
--则输出name值
--[[
__newindex:赋值时，如果赋值一个不存在的索引
那么会把这个值赋值到__newIndex所指的表中，不会修改自己  
如果赋值之后再使用__newindex，还是打印原赋值，不会重新指向
--]]

UnitlModule.PrintOperaName("rawget(),rawset() 和 getmetatable()");

local meta_7 = {age = 18;};
meta_7.__index = {age = 8};
local myTable_8 = {};

setmetatable(myTable_8,meta_7);
myTable_8.name = "设置元表";
print(rawget(myTable_8,"name"));

rawset(myTable_8,"name","第十四节");
print(rawget(myTable_8,"name"));

print(getmetatable(myTable_8).age);
rawset(meta_7,"age",88);
print(myTable_8.age);

--[[
rawget()：获得表的某个变量值，返回该变量值
rawset() ：强制设置变量，且忽略__newindex的设置，只改自己的值
getmetatable()：获得表的元表，返回该元表
--]]